const PACKET_CREATOR = '===SPANNER==='
const PACKET_VERSION = '1.0.0'
const PACKET_ELEMENT = 'iframe'

class WebMessage {
  _dict2json(dict: object): string {
    if (!dict) {
      return ''
    }
    return JSON.stringify(dict)
  }

  _json2dict(json: string) {
    if (!json) {
      return {}
    }
    return JSON.parse(json)
  }

  _unpacketMessage(rawMessage: string) {
    try {
      const payload = this._json2dict(rawMessage)
      if (!payload) {
        return null
      }
      const {
        PacketCreator,
        filter,
        message
      } = payload
      if (!PacketCreator || PacketCreator !== PACKET_CREATOR) {
        return null
      }
      const feedback: {
        filter?: string
        message?: string
      } = {}
      if (filter) {
        feedback.filter = filter
      }
      if (message) {
        feedback.message = message
      }
      return feedback
    } catch (e) {
      return null
    }
  }

  _packetMessage(filter, message): string {
    const payload: {
      PacketCreator: string;
      PacketVersion: string;
      filter?: string;
      message?: string;
    } = {
      PacketCreator: PACKET_CREATOR,
      PacketVersion: PACKET_VERSION,
    }
    if (filter) {
      payload.filter = filter
    }
    if (message) {
      payload.message = message
    }
    return this._dict2json(payload)
  }

  post(message, filter = null, source = '*'): void {
    window?.postMessage(this._packetMessage(filter, message), source)
  }

  postToGlobal(message, filter = null, source = '*'): void {
    const root = window.top
    if (root) {
      root.postMessage(this._packetMessage(filter, message), source)
    }
  }

  postToParent(message, filter = null, source = '*'): void {
    const root = window.parent
    if (root) {
      root.postMessage(this._packetMessage(filter, message), source)
    }
  }

  postToChildren(message, filter = null, source = '*'): void {
    if (document.getElementsByTagName) {
      const frames = document.getElementsByTagName(PACKET_ELEMENT)
      for (const index in frames) {
        const subIframe = frames[index]
        if (subIframe && subIframe.contentWindow) {
          subIframe.contentWindow?.postMessage(this._packetMessage(filter, message), source)
        }
      }
    }
  }

  listener(handle, filter = null) {
    const handlerPack = (event) => {
      if (!handle) {
        return
      }
      const payload = this._unpacketMessage(event.data)
      if (!payload) {
        return
      }
      const msgFilter = payload.filter
      if (filter && filter !== msgFilter) {
        return
      }
      handle(payload.message, event.origin)
    }
    if (window.addEventListener) {
      window.addEventListener('message', handlerPack, false)
    } else if ((window as any).attachEvent) {
      (window as any).attachEvent('onmessage', handlerPack)
    }
  }
}

export default new WebMessage()
